/* Declarations for the tuple type.

   This file is part of khipu.

   khipu is free software: you can redistribute it and/or modify
   it under the terms of the GNU Lesser General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */

#ifndef __KP_TUPLE__
#define __KP_TUPLE__

#include "thread.hpp"

KP_DECLS_BEGIN

struct tuple : public varobj
{
  static const int code = typecode::TUPLE;

  object head;
  object test;
  atomic_t hi_water;

  struct iterator
    {
      iterator (interpreter *interp, object tup);
      iterator (interpreter *interp) : node (interp, 0)
        {
        }

      iterator (interpreter *interp, const iterator& right) :
          iterator (interp)
        {
          this->reset (*right.node);
        }

      bool valid () const
        {
          return (*this->node != 0);
        }

      iterator& operator++ ();
      iterator operator++ (int);

      object operator* () const;

      void reset (object node)
        {
          *this->node = node;
        }

      static iterator make (interpreter *interp, object node)
        {
          iterator rv { interp };
          rv.reset (node);
          return (rv);
        }

      valref node;
    };
};

inline tuple* as_tuple (object obj)
{
  return ((tuple *)unmask (obj));
}

inline bool tuple_p (object obj)
{
  return (itype (obj) == typecode::TUPLE);
}

struct stream;
struct io_info;
struct pack_info;

// Allocate a tuple using TST as the comparator.
KP_EXPORT object alloc_tuple (interpreter *interp, object tst);

/* Get the key that compares equal to KEY in tuple TUP. If not
 * present, return DFL. MTSAFE specifies whether we should use a
 * multi-thread safe routine or not. */
KP_EXPORT object tuple_get (interpreter *interp,
  object tup, object key, object dfl, bool mtsafe);

/* Insert key KEY in tuple TUP. MTSAFE is used in the same manner
 * as with 'tuple_get'. */
KP_EXPORT bool tuple_put (interpreter *interp,
  object tup, object key, bool mtsafe);

/* Remove the key that compares equal to KEY in tuple TUP,
 * and return it. If not present, return DFL. MTSAFE is used in
 * the same manner as with the rest of the API. */
KP_EXPORT object tuple_pop (interpreter *interp,
  object tup, object key, object dfl, bool mtsafe);

/* Shortcuts for the above, where the MTSAFE parameter is deduced
 * from the number of running threads. */

KP_EXPORT object get_o (interpreter *interp,
  object tup, object key, object dfl);

KP_EXPORT object nput_o (interpreter *interp,
  object tup, object key, object val);

KP_EXPORT object npop_o (interpreter *interp,
  object tup, object key, object dfl);

// Fetch the number of elements in tuple TUP.
KP_EXPORT uint32_t len_o (object tup);

// Compute the hashcode for the tuple TUP.
KP_EXPORT uint32_t hash_o (interpreter *interp, object tup);

// Iterator interface for tuples.
KP_EXPORT object iter_o (interpreter *interp,
  object obj, object token, bool adv);

// Write a tuple to a stream.
KP_EXPORT int write_o (interpreter *interp,
  stream *strm, object tup, io_info& info);

// Serialize a tuple in a stream.
KP_EXPORT int64_t pack_o (interpreter *interp,
  stream *strm, object tup, pack_info& info);

// Deserialize a tuple from a stream.
KP_EXPORT object unpack_o (interpreter *interp,
  stream *strm, pack_info& info, bool save);

// Copy a tuple.
KP_EXPORT object copy_o (interpreter *interp, object tup, bool deep);

// Clear a tuple.
KP_EXPORT void tuple_clr (interpreter *interp, object tup);

// Mutate a key inside a tuple.
KP_EXPORT object nzap_o (interpreter *interp, object tup, object key,
  uint32_t flags, object fn, object *argv, int argc);

// Compute the union of tuples TUPLE1 and TUPLE2.
KP_EXPORT object tuple_union (interpreter *interp,
  object tuple1, object tuple2);

// Compute the intersection of tuples TUPLE1 and TUPLE2.
KP_EXPORT object tuple_intersect (interpreter *interp,
  object tuple1, object tuple2);

// Compute the difference of tuples TUPLE1 and TUPLE2.
KP_EXPORT object tuple_diff (interpreter *interp,
  object tuple1, object tuple2);

// Compute the symmetric difference of tuples TUPLE1 and TUPLE2.
KP_EXPORT object tuple_symdiff (interpreter *interp,
  object tuple1, object tuple2);

// Return the nearest element to KEY in TUP.
KP_EXPORT object tuple_nearest (interpreter *interp, object tup,
  object key, object *pred = nullptr, object *succ = nullptr);

KP_DECLS_END

#endif
